
import { AdapterInterface, StringHashOptions, ArrayBufferHashOptions, BlobHashOptions } from './AdapterInterface';
import { HashAlgorithm } from '../types';
import CryptoJS from 'crypto-js';
import { processBlobChunks } from '../../fs/helpers';

/**
 * CryptoJS实现类
 * 
 * @description 该类实现了{@link AdapterInterface}接口，使用CryptoJS库进行加密操作
 */
export class CryptoJsAdapter implements AdapterInterface {

  /**
   * 计算字符串哈希值
   * @param {StringHashOptions} options - 字符串哈希选项
   * @returns {Promise<string>} 哈希值
   * @example
   * const adapter = new CryptoJsAdapter();
   * const hash = await adapter.stringHash({
   *   str: 'hello world',
   *   algorithm: HashAlgorithm.SHA256
   * });
   * console.log(hash);
   * // 输出: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
   */
  async stringHash(options: StringHashOptions): Promise<string> {
    const { str, algorithm } = options;
    return this.__stringArraybufferHash(str, algorithm);
  }

  /**
   * 计算ArrayBuffer哈希值
   * @param {ArrayBufferHashOptions} options - ArrayBuffer哈希选项
   * @returns {Promise<string>} 哈希值
   * @example
   * const adapter = new CryptoJsAdapter();
   * const hash = await adapter.arrayBufferHash({
   *   arrayBuffer: new ArrayBuffer(8),
   *   algorithm: HashAlgorithm.SHA256
   * });
   * console.log(hash);
   * // 输出: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
   */
  async arrayBufferHash(options: ArrayBufferHashOptions): Promise<string> {
    const { arrayBuffer, algorithm } = options;
    return this.__stringArraybufferHash(arrayBuffer, algorithm);
  }

  /**
   * 计算Blob哈希值
   * @param {BlobHashOptions} options - Blob哈希选项
   * @returns {Promise<string>} 哈希值
   * @example
   * const adapter = new CryptoJsAdapter();
   * const hash = await adapter.blobHash({
   *   blob: new Blob(['hello world']),
   *   algorithm: HashAlgorithm.SHA256
   * });
   * console.log(hash);
   * // 输出: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
   */
  async blobHash(
    options: BlobHashOptions
  ): Promise<string> {
    const { blob, algorithm, chunkSize = 1024 * 1024, onProgress } = options;

    // 根据算法创建相应的哈希对象
    let hash: any;
    switch (algorithm) {
      case HashAlgorithm.MD5:
        hash = CryptoJS.algo.MD5.create();
        break;
      case HashAlgorithm.SHA1:
        hash = CryptoJS.algo.SHA1.create();
        break;
      case HashAlgorithm.SHA256:
        hash = CryptoJS.algo.SHA256.create();
        break;
      case HashAlgorithm.SHA512:
        hash = CryptoJS.algo.SHA512.create();
        break;
      default:
        throw new Error(`不支持的哈希算法: ${algorithm}`);
    }

    // 使用processBlobChunks处理分块读取
    await processBlobChunks({
      blob,
      chunkSize,
      onChunk: async (chunkArrayBuffer: ArrayBuffer) => {
        const wordArray = CryptoJS.lib.WordArray.create(chunkArrayBuffer);
        hash.update(wordArray);
      },
      onProgress: (progress) => {
        if (onProgress) {
          onProgress(progress);
        }
      }
    });

    // 完成哈希计算
    const hashWordArray = hash.finalize();

    // 转换为十六进制字符串
    return hashWordArray.toString();
  }

  /**
   * 计算字符串或ArrayBuffer的哈希值
   * @param {string | ArrayBuffer} data - 要计算哈希的值
   * @param {HashAlgorithm} algorithm - 哈希算法
   * @returns {Promise<string>} 哈希值
   */
  private async __stringArraybufferHash(data: string | ArrayBuffer, algorithm: HashAlgorithm): Promise<string> {
    return new Promise((resolve, reject) => {
      let wordArrayOrStr: CryptoJS.lib.WordArray | string;
      if (data instanceof ArrayBuffer) {
        wordArrayOrStr = CryptoJS.lib.WordArray.create(data);
      } else {
        wordArrayOrStr = data;
      }
      switch (algorithm) {
        case HashAlgorithm.MD5:
          resolve(CryptoJS.MD5(wordArrayOrStr).toString());
          break;
        case HashAlgorithm.SHA1:
          resolve(CryptoJS.SHA1(wordArrayOrStr).toString());
          break;
        case HashAlgorithm.SHA256:
          resolve(CryptoJS.SHA256(wordArrayOrStr).toString());
          break;
        case HashAlgorithm.SHA512:
          resolve(CryptoJS.SHA512(wordArrayOrStr).toString());
          break;
        default:
          reject(new Error(`不支持的哈希算法: ${algorithm}`));
          break;
      }
    })
  }
}